Podsumowanie jakieś
Celem projektu jest określenie głównych przyczyn stopniowego zmniejszania się długości śledzi oceanicznych wyławionych w Europie.
Zbiór danych do analizy składa się z pomiarów śledzi i warunków w jakich żyją z ostatnich 60 lat. Dane były pobierane z połowów komercyjnych jednostek. W ramach połowu jednej jednostki losowo wybierano od 50 do 100 sztuk trzyletnich śledzi.
Wszystkie dane, są danymi liczbowymi, nie występują żadne dane kategoryczne.
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ggplot2)
library(GGally) # ggpairplot
## Registered S3 method overwritten by 'GGally':
## method from
## +.gg ggplot2
##
## Attaching package: 'GGally'
## The following object is masked from 'package:dplyr':
##
## nasa
library(DT)
library(mice) # for missing data
## Loading required package: lattice
##
## Attaching package: 'mice'
## The following objects are masked from 'package:base':
##
## cbind, rbind
#ibrary(VIM)
library(ggpubr) # ggarange
## Loading required package: magrittr
library(corrplot) # ggarange
## corrplot 0.84 loaded
library(plotly)
##
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
columns_names <- c("length" = "długość złowionego śledzia [cm]",
"cfin1" = "dostępność planktonu [zagęszczenie Calanus finmarchicus gat. 1]",
"cfin2" = "dostępność planktonu [zagęszczenie Calanus finmarchicus gat. 2]",
"chel1" = "dostępność planktonu [zagęszczenie Calanus helgolandicus gat. 1]",
"chel2" = "dostępność planktonu [zagęszczenie Calanus helgolandicus gat. 2]",
"lcop1" = "dostępność planktonu [zagęszczenie widłonogów gat. 1]",
"lcop2" = "dostępność planktonu [zagęszczenie widłonogów gat. 2]",
"fbar" = "natężenie połowów w regionie [ułamek pozostawionego narybku]",
"recr" = "roczny narybek [liczba śledzi]",
"cumf" = "łączne roczne natężenie połowów w regionie [ułamek pozostawionego narybku]",
"totaln" = "łączna liczba ryb złowionych w ramach połowu [liczba śledzi]",
"sst" = "temperatura przy powierzchni wody [°C]",
"sal" = "poziom zasolenia wody [Knudsen ppt]",
"xmonth" = "miesiąc połowu [numer miesiąca]",
"nao" = "oscylacja północnoatlantycka [mb]" )
prettyTable <- function(table_df, round_columns=numeric(), round_digits=2) {
DT::datatable(table_df, style="bootstrap", filter = "top", rownames = FALSE, extensions = "Buttons", options = list(dom = 'Bfrtip', buttons = c('copy', 'csv', 'excel', 'pdf', 'print'))) %>%
formatRound(round_columns, round_digits)
}
# Multiple plot function
#
# ggplot objects can be passed in ..., or to plotlist (as a list of ggplot objects)
# - cols: Number of columns in layout
# - layout: A matrix specifying the layout. If present, 'cols' is ignored.
#
# If the layout is something like matrix(c(1,2,3,3), nrow=2, byrow=TRUE),
# then plot 1 will go in the upper left, 2 will go in the upper right, and
# 3 will go all the way across the bottom.
#
multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) {
library(grid)
# Make a list from the ... arguments and plotlist
plots <- c(list(...), plotlist)
numPlots = length(plots)
# If layout is NULL, then use 'cols' to determine layout
if (is.null(layout)) {
# Make the panel
# ncol: Number of columns of plots
# nrow: Number of rows needed, calculated from # of cols
layout <- matrix(seq(1, cols * ceiling(numPlots/cols)),
ncol = cols, nrow = ceiling(numPlots/cols))
}
if (numPlots==1) {
print(plots[[1]])
} else {
# Set up the page
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))
# Make each plot, in the correct location
for (i in 1:numPlots) {
# Get the i,j matrix positions of the regions that contain this subplot
matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))
print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
layout.pos.col = matchidx$col))
}
}
}
Pierwszym krokiem jest wczytanie danych oraz bliższe przyjżenie się im. Ponieważ w pliku csv brakujące rekordy zapisane są jako “?” trzeba je poprawnie wczytać.Brakujące dane występują w kolumnach cfin1, cfin2, chel1, chel2, lcop1, lcop2 i lsst. Jako że kolumna x to po prostu numer pomiaru, nie będzie nam potrzebna.
set.seed(23)
data <- read.csv("sledzie.csv", na.strings = c("?"))
lapply(data, function(x) any(is.na(x)))
## $X
## [1] FALSE
##
## $length
## [1] FALSE
##
## $cfin1
## [1] TRUE
##
## $cfin2
## [1] TRUE
##
## $chel1
## [1] TRUE
##
## $chel2
## [1] TRUE
##
## $lcop1
## [1] TRUE
##
## $lcop2
## [1] TRUE
##
## $fbar
## [1] FALSE
##
## $recr
## [1] FALSE
##
## $cumf
## [1] FALSE
##
## $totaln
## [1] FALSE
##
## $sst
## [1] TRUE
##
## $sal
## [1] FALSE
##
## $xmonth
## [1] FALSE
##
## $nao
## [1] FALSE
data <- subset(data, select = -c(X))
summary(data)
## length cfin1 cfin2 chel1
## Min. :19.0 Min. : 0.0000 Min. : 0.0000 Min. : 0.000
## 1st Qu.:24.0 1st Qu.: 0.0000 1st Qu.: 0.2778 1st Qu.: 2.469
## Median :25.5 Median : 0.1111 Median : 0.7012 Median : 5.750
## Mean :25.3 Mean : 0.4458 Mean : 2.0248 Mean :10.006
## 3rd Qu.:26.5 3rd Qu.: 0.3333 3rd Qu.: 1.7936 3rd Qu.:11.500
## Max. :32.5 Max. :37.6667 Max. :19.3958 Max. :75.000
## NA's :1581 NA's :1536 NA's :1555
## chel2 lcop1 lcop2 fbar
## Min. : 5.238 Min. : 0.3074 Min. : 7.849 Min. :0.0680
## 1st Qu.:13.427 1st Qu.: 2.5479 1st Qu.:17.808 1st Qu.:0.2270
## Median :21.673 Median : 7.0000 Median :24.859 Median :0.3320
## Mean :21.221 Mean : 12.8108 Mean :28.419 Mean :0.3304
## 3rd Qu.:27.193 3rd Qu.: 21.2315 3rd Qu.:37.232 3rd Qu.:0.4560
## Max. :57.706 Max. :115.5833 Max. :68.736 Max. :0.8490
## NA's :1556 NA's :1653 NA's :1591
## recr cumf totaln sst
## Min. : 140515 Min. :0.06833 Min. : 144137 Min. :12.77
## 1st Qu.: 360061 1st Qu.:0.14809 1st Qu.: 306068 1st Qu.:13.60
## Median : 421391 Median :0.23191 Median : 539558 Median :13.86
## Mean : 520367 Mean :0.22981 Mean : 514973 Mean :13.87
## 3rd Qu.: 724151 3rd Qu.:0.29803 3rd Qu.: 730351 3rd Qu.:14.16
## Max. :1565890 Max. :0.39801 Max. :1015595 Max. :14.73
## NA's :1584
## sal xmonth nao
## Min. :35.40 Min. : 1.000 Min. :-4.89000
## 1st Qu.:35.51 1st Qu.: 5.000 1st Qu.:-1.89000
## Median :35.51 Median : 8.000 Median : 0.20000
## Mean :35.51 Mean : 7.258 Mean :-0.09236
## 3rd Qu.:35.52 3rd Qu.: 9.000 3rd Qu.: 1.63000
## Max. :35.61 Max. :12.000 Max. : 5.08000
##
paste0("Ilość badanych przypadków: ", nrow(data), ", ilość zmiennych: ", ncol(data))
## [1] "Ilosc badanych przypadków: 52582, ilosc zmiennych: 15"
head(data, 10)
## length cfin1 cfin2 chel1 chel2 lcop1 lcop2 fbar recr
## 1 23.0 0.02778 0.27785 2.46875 NA 2.54787 26.35881 0.356 482831
## 2 22.5 0.02778 0.27785 2.46875 21.43548 2.54787 26.35881 0.356 482831
## 3 25.0 0.02778 0.27785 2.46875 21.43548 2.54787 26.35881 0.356 482831
## 4 25.5 0.02778 0.27785 2.46875 21.43548 2.54787 26.35881 0.356 482831
## 5 24.0 0.02778 0.27785 2.46875 21.43548 2.54787 26.35881 0.356 482831
## 6 22.0 0.02778 0.27785 2.46875 21.43548 2.54787 NA 0.356 482831
## 7 24.0 0.02778 0.27785 2.46875 21.43548 2.54787 26.35881 0.356 482831
## 8 23.5 0.02778 0.27785 2.46875 21.43548 2.54787 26.35881 0.356 482831
## 9 22.5 0.02778 0.27785 2.46875 21.43548 2.54787 26.35881 0.356 482831
## 10 22.5 0.02778 0.27785 2.46875 21.43548 2.54787 26.35881 0.356 482831
## cumf totaln sst sal xmonth nao
## 1 0.3059879 267380.8 14.30693 35.51234 7 2.8
## 2 0.3059879 267380.8 14.30693 35.51234 7 2.8
## 3 0.3059879 267380.8 14.30693 35.51234 7 2.8
## 4 0.3059879 267380.8 14.30693 35.51234 7 2.8
## 5 0.3059879 267380.8 14.30693 35.51234 7 2.8
## 6 0.3059879 267380.8 14.30693 35.51234 7 2.8
## 7 0.3059879 267380.8 14.30693 35.51234 7 2.8
## 8 0.3059879 267380.8 14.30693 35.51234 7 2.8
## 9 0.3059879 267380.8 14.30693 35.51234 7 2.8
## 10 0.3059879 267380.8 14.30693 35.51234 7 2.8
W celu poradzenia sobie z brakującymi danymi zostaje wykorzystana metoda MICE (Multivariate Imputation via Chained Equations). Metoda ta pozwala na pozbycie się brakujących danych z utrzymaniem podobnego rozkład
plot_histograms <- function(data, columns=NULL, ncol=1, nrow=1, createName=function(x) x){
if(is.null(columns)){
columns <- names(data)
}
i <- 1
plots <- list()
for (column_name in columns){
p <- ggplot(data, aes_string(x = column_name)) +
geom_histogram(color="black", fill="orange") +
ggtitle(createName(column_name)) +
ylab("Liczba obserwacji")
plots[[i]] <- p
i <- i + 1
}
figure <- ggarrange(plotlist = plots, ncol = ncol, nrow = nrow)
# annotate_figure(figure, top = text_grob("dddDDDD"))
figure
}
missing_data_columns <- c("cfin1", "cfin2", "chel1", "chel2", "lcop1", "lcop2", "sst")
plot_histograms(data, columns = missing_data_columns, createName = function(x) paste0("Histogram ", x, " przed pozbyciem się brakujących danych"), nrow=2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 1581 rows containing non-finite values (stat_bin).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 1536 rows containing non-finite values (stat_bin).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 1555 rows containing non-finite values (stat_bin).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 1556 rows containing non-finite values (stat_bin).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 1653 rows containing non-finite values (stat_bin).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 1591 rows containing non-finite values (stat_bin).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 1584 rows containing non-finite values (stat_bin).
## $`1`
##
## $`2`
##
## $`3`
##
## $`4`
##
## attr(,"class")
## [1] "list" "ggarrange"
# mice_plot <- aggr(data, col=c('navyblue','yellow'),
# numbers=TRUE, sortVars=TRUE,
# labels=names(data), cex.axis=.7,
# gap=3, ylab=c("Missing data","Pattern"))
completed_data <- data %>%
mice(m=5, method = 'cart', seed = 63) %>%
complete(2)
##
## iter imp variable
## 1 1 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 1 2 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 1 3 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 1 4 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 1 5 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 2 1 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 2 2 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 2 3 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 2 4 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 2 5 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 3 1 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 3 2 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 3 3 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 3 4 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 3 5 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 4 1 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 4 2 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 4 3 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 4 4 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 4 5 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 5 1 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 5 2 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 5 3 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 5 4 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
## 5 5 cfin1 cfin2 chel1 chel2 lcop1 lcop2 sst
plot_histograms(completed_data, columns = missing_data_columns, createName = function(x) paste0("Histogram ", x, " po pozbyciu się brakujących danych"), nrow=2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## $`1`
##
## $`2`
##
## $`3`
##
## $`4`
##
## attr(,"class")
## [1] "list" "ggarrange"
# Plots could be better, but R is stupid language and I have problem with it.
make.assign_year <- function() {
last_year <- 0
last_month <- completed_data$xmonth[1]
assign_year <- function(month){
lm <- last_month
if(month < last_month){
last_year <<- last_year + 1
}
last_month <<- month
print(gettextf("%d %d", last_month, lm))
last_year
}
return(assign_year)
}
assign_year <-
assign_year(8)
assign_year(8)
assign_year(9)
assign_year(1)
assign_year(2)
assign_year(0)
last_month
Podsumowanie danych
summary(completed_data)
## length cfin1 cfin2 chel1
## Min. :19.0 Min. : 0.0000 Min. : 0.0000 Min. : 0.000
## 1st Qu.:24.0 1st Qu.: 0.0000 1st Qu.: 0.2778 1st Qu.: 2.469
## Median :25.5 Median : 0.1111 Median : 0.7012 Median : 5.750
## Mean :25.3 Mean : 0.4459 Mean : 2.0258 Mean :10.001
## 3rd Qu.:26.5 3rd Qu.: 0.3333 3rd Qu.: 1.7936 3rd Qu.:11.500
## Max. :32.5 Max. :37.6667 Max. :19.3958 Max. :75.000
## chel2 lcop1 lcop2 fbar
## Min. : 5.238 Min. : 0.3074 Min. : 7.849 Min. :0.0680
## 1st Qu.:13.427 1st Qu.: 2.5479 1st Qu.:17.808 1st Qu.:0.2270
## Median :21.673 Median : 7.0000 Median :24.859 Median :0.3320
## Mean :21.221 Mean : 12.8066 Mean :28.423 Mean :0.3304
## 3rd Qu.:27.193 3rd Qu.: 21.2315 3rd Qu.:37.232 3rd Qu.:0.4560
## Max. :57.706 Max. :115.5833 Max. :68.736 Max. :0.8490
## recr cumf totaln sst
## Min. : 140515 Min. :0.06833 Min. : 144137 Min. :12.77
## 1st Qu.: 360061 1st Qu.:0.14809 1st Qu.: 306068 1st Qu.:13.60
## Median : 421391 Median :0.23191 Median : 539558 Median :13.86
## Mean : 520367 Mean :0.22981 Mean : 514973 Mean :13.87
## 3rd Qu.: 724151 3rd Qu.:0.29803 3rd Qu.: 730351 3rd Qu.:14.16
## Max. :1565890 Max. :0.39801 Max. :1015595 Max. :14.73
## sal xmonth nao
## Min. :35.40 Min. : 1.000 Min. :-4.89000
## 1st Qu.:35.51 1st Qu.: 5.000 1st Qu.:-1.89000
## Median :35.51 Median : 8.000 Median : 0.20000
## Mean :35.51 Mean : 7.258 Mean :-0.09236
## 3rd Qu.:35.52 3rd Qu.: 9.000 3rd Qu.: 1.63000
## Max. :35.61 Max. :12.000 Max. : 5.08000
Histogramy wartości atrybutów w zbiorze danych
plot_histograms(completed_data, createName = function(x) paste0("Histogram - ", columns_names[x]), nrow=1)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## $`1`
##
## $`2`
##
## $`3`
##
## $`4`
##
## $`5`
##
## $`6`
##
## $`7`
##
## $`8`
##
## $`9`
##
## $`10`
##
## $`11`
##
## $`12`
##
## $`13`
##
## $`14`
##
## $`15`
##
## attr(,"class")
## [1] "list" "ggarrange"
Poniżej została przedstawiona korelacja pomiędzy atrybutami. Można zauważyć, że występuje wysoka korelacja pomiędzy parami atrybutów chel1-lcop1, chel2-lcop2 oraz fbar-cumf. Korelacja może występować, ponieważ, dwie pierwsze pary związane są z dostępnością zaś ostatnia para korelacji może występować, ponieważ obydwa atrybuty związane są z natężeniem popłowu w regionie. Można te pary zredukować, aby przeciwdziałać klątwie wielowymiarowości - jednakże tutaj zostaną one zostawione bez zmian.
corrplot(cor(completed_data), type = "upper", tl.col = "black", tl.srt = 45, method="number")
ggplot(completed_data, aes(x=chel1, y=lcop1)) +
geom_point() +
geom_smooth(method=lm) +
ggtitle("Zależność pomiędzy atrybytem chel1 i lcop1")
linear_model_1 <- lm(chel1 ~ lcop1, data = completed_data)
ggplot(completed_data, aes(x=chel2, y=lcop2)) +
geom_point() +
geom_smooth(method=lm) +
ggtitle("Zależność pomiędzy atrybytem chel2 i lcop2")
linear_model_2 <- lm(chel2 ~ lcop2, data = completed_data)
ggplot(completed_data, aes(x=fbar, y=cumf)) +
geom_point() +
geom_smooth(method=lm) +
ggtitle("Zależność pomiędzy atrybytem fbar i cumf")
linear_model_3 <- lm(fbar ~ cumf, data = completed_data)
Poniżej przedstawiona została analiza długości śledzia na przestrzeni czasu. Jednakże czas nie był przedstawiony jawnie, ale wiadomo, że dane są ustawione chronologicznie dzięki czemu, zbiór można podzielić i na każdym z podziałów policzyć średnią.
cases_per_aggregate <- 200
aggregated_data <- aggregate(completed_data,
list(rep(1:(nrow(completed_data)%/%cases_per_aggregate+1), each=cases_per_aggregate, len=nrow(completed_data))),
mean) # Try using mean without outliners
aggregated_data$time_period = c(1:nrow(aggregated_data))
ggplot(aggregated_data, aes(time_period, length)) +
geom_point() +
geom_smooth() +
ggtitle("Wykres zmiany długości śledzia na przestrzeni czasu") +
ylab("Długość śledzia") +
xlab("Przedział czasowy")
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'
plot_ly(data = aggregated_data, x = ~time_period, y = ~length,
text = ~paste("Length: ", length))
## No trace type specified:
## Based on info supplied, a 'scatter' trace seems appropriate.
## Read more about this trace type -> https://plot.ly/r/reference/#scatter
## No scatter mode specifed:
## Setting the mode to markers
## Read more about this attribute -> https://plot.ly/r/reference/#scatter-mode
# %>% layout(
# scene = list(
# xaxis = list(title = "Przedział czasowy"),
# yaxis = list(title = "Długość śledzia")
# )
# )
Do usunięcia później TODO 5. Sekcję podsumowującą rozmiar zbioru i podstawowe statystyki. 9. Sekcję próbującą stworzyć regresor przewidujący rozmiar śledzia (w tej sekcji należy wykorzystać wiedzę z pozostałych punktów oraz wykonać dodatkowe czynności, które mogą poprawić trafność predykcji); dobór parametrów modelu oraz oszacowanie jego skuteczności powinny zostać wykonane za pomocą techniki podziału zbioru na dane uczące, walidujące i testowe; trafność regresji powinna zostać oszacowana na podstawie miar R2 i RMSE. 10. Analizę ważności atrybutów najlepszego znalezionego modelu regresji. Analiza ważności atrybutów powinna stanowić próbę odpowiedzi na pytanie: co sprawia, że rozmiar śledzi zaczął w pewnym momencie maleć.
Done 1. Kod wyliczający wykorzystane biblioteki. 2. Kod zapewniający powtarzalność wyników przy każdym uruchomieniu raportu na tych samych danych. 3. Kod pozwalający wczytać dane z pliku. 4. Kod przetwarzający brakujące dane. 6. Szczegółową analizę wartości atrybutów (np. poprzez prezentację rozkładów wartości). 7. Sekcję sprawdzającą korelacje między zmiennymi; sekcja ta powinna zawierać jakąś formę graficznej prezentacji korelacji. 8. Interaktywny wykres lub animację prezentującą zmianę rozmiaru śledzi w czasie.